<template>
  <div class="image-container">
    <el-card class="box-card">
      <div slot="header">
        <el-breadcrumb separator-class="el-icon-arrow-right">
          <el-breadcrumb-item to="/">首页</el-breadcrumb-item>
          <el-breadcrumb-item>素材管理</el-breadcrumb-item>
        </el-breadcrumb>
      </div>
      <div style="padding-bottom: 20px;">
        <!--
        1.自定义属性size决定了单选框的大小
        2.最终双向绑定到radio1上面的值是label
        -->
        <el-radio-group v-model="collect" size="mini" @change="collectChange">
          <el-radio-button :label="false">全部</el-radio-button>
          <el-radio-button :label="true">收藏</el-radio-button>
        </el-radio-group>
        <el-button @click="showDialog" type="success" size="mini" style="float:right">上传图片素材</el-button>
      </div>
      <!-- 素材列表 -->
      <!-- 栅格系统的应用 -->
      <!-- .native 修饰符-->
      <el-row :gutter="10">
        <el-col
          @mouseenter.native="mEnter(image)"
          @mouseleave.native="mLeave(image)"
          v-for="(image,idx) in imageList"
          :key="image.id"
          class="img_item"
          :xs="12"
          :sm="6"
          :md="6"
          :lg="4"
        >
          <div class="img_box">
            <img :src="image.url" alt />
          </div>
          <div class="option" v-show="image.isShow">
            <!-- 
              image.is_collected  true  false 
              true 表示  已收藏
              false  表示未被收藏
            -->
            <span
              class="el-icon-star-off"
              @click="hSwitchCollect(image)"
              :style="{color:image.is_collected?'red':'#fff'}"
            ></span>
            <span class="el-icon-delete" @click="hDelImage(image.id,idx)"></span>
          </div>
        </el-col>
      </el-row>
      <!-- /素材列表 -->
      <!--
        前端  总数(17)/ 每页条数(10) =  页数 2 
        后端  总数(17)/ 每页条数(20) =  页数 1
        解决方案：把每页条数前后端保持一致
      -->
      <el-pagination
        style="margin-top: 10px"
        layout="sizes,prev, pager, next"
        :page-sizes="[5, 10, 15, 20]"
        :page-size="10"
        :total="total_count"
        @current-change="pageChange"
        @size-change="handleSizeChange"
      ></el-pagination>
    </el-card>
    <!-- Dialog 弹出一个对话框，适合需要定制性更大的场景。 -->
    <!-- 将内层 Dialog 的该属性设置为 true，它就会插入至 body 元素上，从而保证内外层 Dialog 和遮罩层级关系的正确。
    append-to-body 将弹出框和遮罩层设置为都成为body的第一层子元素
    z-index弹出框要大于遮罩层  所以会进行覆盖
    -->
    <el-dialog title="提示" :visible.sync="dialogVisible" append-to-body>
      <!-- action:图片上传接口地址
      :headers 代表接口的请求头设置
      on-success:代表图片上传成功之后的回调函数
      before-upload:代表图片上传之前要进行的处理  经常用来检测图片的大小和格式是否满足要求
      name="image" 代表上传时候的文件字段名称  供后端用来获取
      -->
      <el-upload
        class="uploadBox"
        action="http://ttapi.research.itcast.cn/mp/v1_0/user/images"
        :headers="headers"
        name="image"
        :show-file-list="false"
        :on-success="handleSuccess"
        :before-upload="beforeUpload"
      >
        <img v-if="imageUrl" :src="imageUrl" class="avatar" />
        <i v-else class="el-icon-plus avatar-uploader-icon"></i>
      </el-upload>
      <span slot="footer" class="dialog-footer"></span>
    </el-dialog>
  </div>
</template>

<script>
// 1. 控制操作区域的显示实际上控制的一个数据的状态
// 2. 每个素材应该各自有各自控制显示隐藏的状态数据
//3. 基于现在每个素材依赖的数据 我们添加一项自己的专门用来控制显示和隐藏的数据
// 4.默认状态下所有的素材都不展示出来操作框
//5. 绑定事件控制当前项的isShow属性true和false 
//6.根据拿到的当前素材的id 去list中匹配，然后找到要修改的项  将其isShow修改掉 
import { getImages, switchCollect, delImage } from '@/api/images'
import { getUser } from '@/store'
export default {
  name: 'ImageIndex',
  data() {
    return {
      imageList: [],
      total_count: 0,
      curPgae: 1,//当前要请求第几页数据
      per_page: 10,//每页的条数
      collect: false,//是否是收藏的图片  也就是全部数据
      dialogVisible: false,
      //图片上传的请求头 token设置
      headers: {
        Authorization: `Bearer ${getUser().token}`
      },
      imageUrl: ''//图片预览地址
    }
  },
  methods: {
    //获取素材
    hGetImages() {
      getImages({
        page: this.curPgae,
        per_page: this.per_page,
        collect: this.collect
      }).then(res => {
        console.log(res)
        //直接进行赋值操作
        //处理之后才能进行赋值 （为每一项素材数据中都添加一个自己的新的数据状态用来控制显示/隐藏）
        //数据处理
        let list = res.data.data.results
        let newList = list.map((item) => {
          return {
            ...item,//原项
            isShow: false//不展示
          }
        })
        // console.log(newList)
        this.imageList = newList
        //拿到总数，赋值给total_count
        this.total_count = res.data.data.total_count
      })
    },
    pageChange(pageNum) {
      console.log('change' + pageNum)
      //更改当前要传递给后端的页数
      this.curPgae = pageNum
      //用当前页作为参数，请求当前页的数据
      this.hGetImages()
    },
    //每页条数发生变化的时候触发
    handleSizeChange(pageSize) {
      //核心逻辑：前端per_page更改为当前你选择每页的条数  后端的per_page页更改为你修改之后的每页的条数
      this.per_page = pageSize
      //重新渲染
      this.hGetImages()
    },
    //切换全部和收藏时调用
    // 点击切换 拿到当前的collect 然后用新的collect 值去请求数据 
    collectChange(collect) {
      //不需要把实参传递过来的值  当成参数传递给后端  因为当我切换的时候  this.collect 已经变了
      // console.log(collect)
      //在实际发生请求之前打印一下当前的 this.collect
      // console.log(this.collect)
      //elementUI 双向绑定  和  事件触发取值 应该用哪个？
      //判断依据：在事件触发的时候打印一下双向绑定的值看看是不是能拿到最新的值！
      //如果是一样的就直接使用双向绑定的值  如果不一样就需要使用实参传递进来的值
      this.hGetImages()
    },
    //移入  显示 isShow 为 true
    mEnter(image) {
      image.isShow = true
    },
    //移出  隐藏 isShow 为 false
    mLeave(image) {
      image.isShow = false
    },
    //收藏和取消收藏
    hSwitchCollect(image) {
      console.log(image)
      //es6 中的解构赋值  image  {id:xxx , is_collected:true , url:""}
      //let id=im试图
      //let is_collected=image.is_collected
      let { id, is_collected } = image
      //能控制视图发生变化的前提是试图依赖的数据是响应式的
      //通过解构出来的属性已经不是响应式数据了，所以不会影响到试图
      switchCollect(id, !is_collected).then(res => {
        //成功回调 
        // 如果当前的is_collected是true  那传给后端的应该是false 
        // 如果当前的is_collected是false  那传给后端的应该是true 
        // console.log(res)
        //1.重新请求一下列表，用更改之后的数据重新渲染试图
        //2.不去拉数据  而是把本地的数据对应的数据状态修改一下
        //采取第二种方案进行状态更改从而更新试图

        //总结：1.调用接口  修改数据库中当前素材的收藏状态  保证你在刷新列表的时候能拿到正确的数据
        //2.需要更改本地的数据状态  保证试图的状态显示和实际的数据一致  性能更好
        image.is_collected = !image.is_collected

      })
    },
    hDelImage(id, idx) {
      console.log(id, idx)
      //危险操作都提示一下用户确认是否真的要删除
      this.$confirm('确认删除此素材吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        delImage(id).then(res => {
          // 数据方法删除
          //方法一  this.hGetImages()
          //方法二  删除成功以后  更新一下本地数据  将删除的那项清掉
          this.imageList.splice(idx, 1)//推荐
          this.$message({
            type: 'success',
            message: '删除成功!'
          })
        })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        })
      })
    },
    //图片上传成功方法
    handleSuccess(response, file, fileList) {
      // console.log('图片上传成功了')
      // console.log(response, file, fileList)
      //成功之后回显
      let url = response.data.url
      this.imageUrl = url
      this.$message('上传素材成功')
      //上传成功以后重新拉数据
      this.hGetImages()
      //自己加的,上传图片成功之后提示框隐藏
      setTimeout(() => {
        this.dialogVisible = false
      }, 1000)
    },
    ///上传前做校验  以后工作中都要做  服务器的限制  网关的限制
    beforeUpload(file) {
      console.log(file)//file是当前上传的文件对象  里面有我们需要的属性  比如说大小  类型  名称等等
      //校验规则：type JPG  size<2M  依据产品逻辑
      const isJPG = file.type === 'image/jpeg'
      // 1M=1024kb  1kb=1024b
      const isLt2M = file.size / 1024 / 1024 < 2;

      if (!isJPG) {
        this.$message.error('上传头像图片只能是 JPG 格式!')
      }
      if (!isLt2M) {
        this.$message.error('上传头像图片大小不能超过 2MB!')
      }
      //返回值必须是个布尔值类型   如果为true 代表校验通过  继续执行真正的上传逻辑
      //如果为false  就不再执行真正的上传逻辑
      return isJPG && isLt2M
    },
    showDialog() {
      this.imageUrl = ''
      this.dialogVisible = true
    }
  },
  mounted() {
    this.hGetImages()
  }
}
</script>

<style lang="less" scoped>
// scoped 代表当前的样式只能影响当前的组件  影响不了子组件的样式
.img_item {
  position: relative;
  box-sizing: border-box;
  .img_box {
    height: 180px;
    img {
      width: 100%;
      height: 100%;
    }
  }
}
.option {
  position: absolute;
  left: 5px;
  right: 5px;
  bottom: 5px;
  height: 30px;
  background: rgba(0, 0, 0, 0.3);
  color: #fff;
  display: flex;
  span {
    flex: 1;
    text-align: center;
    cursor: pointer;
    line-height: 30px;
  }
}

.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  line-height: 178px;
  text-align: center;
}
.uploadBox {
  text-align: center;
  img {
    width: 100%;
  }
  // 深度作用选择器 因为里面的盒子在组件里找不到，所以需要用到deep
  //加上 /deep/ 之后可以进行深度样式控制
  //当试图直接控制子组件内部元素样式的时候就需要添加 /deep/
  /deep/ .el-upload {
    border: 1px dashed #d9d9d9;
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
  }
}
.v-modal {
  opacity: 1;
}
</style>

